package ro.upt.dcda.pricezone.common;

import java.util.HashMap;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.StreamMessage;

public class Server extends Thread {

	private final QueueReceiver receiver;
	private final QueueSender sender;
	private volatile boolean shouldRun = true;
	private final HashMap<String, Message> receivedMessages = new HashMap<>();
	private static int msgId = 0;
	private QueueSession session;
	private String name;

	public Server(String name, Queue in, Queue out, QueueSession session)
			throws JMSException {
		this.session = session;
		receiver = session.createReceiver(in);
		sender = session.createSender(out);
		this.name = name;
	}

	public String getServerName() {
		return name;
	}

	public void sendMessage(Message message) throws JMSException {
		synchronized (sender) {
			message.setJMSCorrelationID("" + (msgId++));
			sender.send(message);
			sendFake();
		}
	}

	public StreamMessage createStreamMessage() throws JMSException {
		return session.createStreamMessage();
	}

	public void stopServer() {
		shouldRun = false;
	}

	public Message getMessage(String messageId) {
		synchronized (receivedMessages) {
			return receivedMessages.remove(messageId);
		}
	}

	public Message getResponseFor(Message message, long waitTime)
			throws JMSException {
		sendMessage(message);
		Message msg = null;
		while (msg == null && waitTime > 0) {
			try {
				synchronized (receivedMessages) {
					msg = getMessage(message.getJMSCorrelationID());
					if (msg != null) {
						return msg;
					}
					waitTime -= 100;
					receivedMessages.wait(100);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("Giving up for request"
				+ message.getJMSCorrelationID());
		return null;
	}

	private void sendFake() throws JMSException {
		synchronized (sender) {
			for (int i = 0; i < 5; i++) {
				StreamMessage response = session.createStreamMessage();
				response.setJMSCorrelationID("fake");
				response.writeString("fake");
				response.reset();
				sender.send(response);
			}
		}
	}

	@Override
	public void run() {
		while (shouldRun) {
			try {
				Message msg = receiver.receiveNoWait();
				if (msg == null) {
					synchronized (this) {
						wait(50);
					}
					continue;
				}
				synchronized (receivedMessages) {
					if (msg.getJMSCorrelationID().equals("fake")) {
						continue;
					}
					System.out.println("Server received message:"
							+ msg.getJMSCorrelationID());
					receivedMessages.put(msg.getJMSCorrelationID(), msg);
					receivedMessages.notify();
				}
			} catch (Exception ex) {
				ex.printStackTrace(System.out);
			}
		}
	}
}
